//! # PlayerState - 播放器状态
//!
//! 播放器状态用于保存播放器的状态，包括映射器、播放器、停止信号、播放任务。
//!
//! 映射器用于将 MIDI 事件映射到实际的功能上。

use std::{path::PathBuf, sync::Arc, time::Duration};

use mp4game::{mapper::MidiMapper, player::MidiPlayer};

use tokio::{
    sync::{oneshot, Mutex},
    task::JoinHandle,
};

use crate::config::mapper::MapperConfig;

/// 播放器状态
pub struct PlayerState<'a> {
    /// 映射器
    mapper: Arc<Mutex<Box<dyn MidiMapper>>>,
    /// 播放器
    player: Arc<MidiPlayer<'a>>,
    /// 停止信号
    stop: Arc<Mutex<bool>>,
    /// 播放任务
    play_task: Arc<Mutex<Option<JoinHandle<()>>>>,
}

impl<'a> PlayerState<'a> {
    /// 新建播放器
    ///
    /// # 参数
    ///
    /// * `mapper` - 映射器
    /// * `path` - Midi 文件路径
    ///
    /// # 返回值
    ///
    /// * `Ok(PlayerState)` - 播放器状态
    /// * `Err(String)` - 错误信息
    pub fn new(mapper: &MapperConfig, path: PathBuf) -> Result<Self, String> {
        Ok(Self {
            mapper: Arc::new(Mutex::new(
                mapper.create_mapper().map_err(|e| format!("{e:?}"))?,
            )),
            player: Arc::new(MidiPlayer::from_path(path).map_err(|e| format!("{e:?}"))?),
            stop: Arc::new(Mutex::new(true)),
            play_task: Arc::new(Mutex::new(None)),
        })
    }

    /// 管理播放任务
    ///
    /// # 参数
    ///
    /// * `mute` - 是否静音
    /// * `start_point` - 开始播放的位置
    /// * `sender` - 停止信号
    ///
    /// # 示例
    ///
    /// ```
    /// let (sender, receiver) = oneshot::channel();
    /// state.track_loop(false, None, sender).await;
    /// ```
    async fn track_loop(
        &mut self,
        mute: bool,
        start_point: Option<Duration>,
        sender: oneshot::Sender<bool>,
    ) {
        // 保证停止
        self.stop().await;

        // 获取资源
        let mapper = self.mapper.clone();
        let player =
            unsafe { std::mem::transmute::<_, Arc<MidiPlayer<'static>>>(self.player.clone()) };
        let stop = self.stop.clone();

        // 开始
        *self.stop.lock().await = false;
        *self.play_task.lock().await = Some(tokio::spawn(async move {
            let stop2 = stop.clone();

            // 根据 mute 决定播放方式（播放/转换）
            if mute {
                player.convert(mapper, start_point, Some(stop2)).await
            } else {
                player.play(mapper, start_point, Some(stop2)).await
            }

            // 发送停止信号
            let _ = sender.send(*stop.lock().await);
        }));
    }

    /// 播放
    ///
    /// # 参数
    ///
    /// * `start_point` - 开始播放的位置
    /// * `sender` - 停止信号
    ///
    /// # 示例
    ///
    /// ```
    /// let (sender, receiver) = oneshot::channel();
    /// state.play(None, sender).await;
    /// ```
    pub async fn play(&mut self, start_point: Option<Duration>, sender: oneshot::Sender<bool>) {
        self.track_loop(false, start_point, sender).await;
    }

    /// 转换
    ///
    /// # 参数
    ///
    /// * `start_point` - 开始播放的位置
    /// * `sender` - 停止信号
    ///
    /// # 示例
    ///
    /// ```
    /// let (sender, receiver) = oneshot::channel();
    /// state.convert(None, sender).await;
    /// ```
    pub async fn convert(&mut self, start_point: Option<Duration>, sender: oneshot::Sender<bool>) {
        self.track_loop(true, start_point, sender).await;
    }

    /// 停止
    ///
    /// # 示例
    ///
    /// ```
    /// state.stop().await;
    /// ```
    pub async fn stop(&mut self) {
        if let Some(t) = &mut *self.play_task.lock().await {
            if !t.is_finished() {
                *self.stop.lock().await = true;
                let _ = t.await;
            }
        }
        *self.play_task.lock().await = None;
    }

    /// 是否正在播放
    pub async fn on_track(&self) -> bool {
        match &*self.play_task.lock().await {
            None => false,
            Some(t) => !t.is_finished(),
        }
    }

    /// 获取 Midi 时长
    pub async fn duration(&self) -> Duration {
        self.player.duration().await
    }
}
